﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Tzx.UpdateReminder
{
    /// <summary>
    /// 更新检查器,示例:在html中含有以下字符:
    /// <![CDATA[ 
    /// <div>最新版本：<span id="A75A3EDFED144bde9F54D21A8481C594_version"  >1.201.3305.1212</span></div> 
    /// <div>下载地址：<span id="A75A3EDFED144bde9F54D21A8481C594_url"  >http://tangzhongxin.blog.163.com/blog/static/8921961201302325725988/</span></div> 
    /// <div>更新说明：<span id="A75A3EDFED144bde9F54D21A8481C594_readme"  >有好多更新说明呀，不要忘记了啊！</span></div>
    /// ]]>
    /// </summary>
    public class UpdateReminder
    {
        #region 常量文本

        /// <summary>
        /// 后缀_版本号
        /// </summary>
        private const string SuffixID_Version = "_version";

        /// <summary>
        /// 后缀_下载Url
        /// </summary>
        private const string SuffixID_DownloadUrl = "_url";

        /// <summary>
        /// 后缀_更新说明
        /// </summary>
        private const string SuffixID_Readme = "_readme";

        #endregion

        #region 搜索版本信息的正则表达式模式(Pattern)

        /// <summary>
        /// 版本号,如"1.201.3305.1212"
        /// </summary>
        protected string Pattern_Version
        {
            get
            {
                string pattern_Version =
                    @"<span\s{1,}id=""" +
                    _appUniqueMark +
                    SuffixID_Version +
                    @"""\s{0,}>\s{0,}\d{1,}.\d{1,}.\d{1,}.\d{1,}\s{0,}</span>";
                return pattern_Version;
            }
        }

        /// <summary>
        /// 下载Url,如"http://tangzhongxin.blog.163.com/blog/static/download/DemoApp.zip"
        /// </summary>
        protected string Pattern_DownloadUrl
        {
            get
            {
                string pattern_DownloadUrl =
                    @"<span\s{1,}id=""" +
                    _appUniqueMark +
                    SuffixID_DownloadUrl +
                    @"""\s{0,}>\s{0,}\S{1,}\s{0,}</span>";
                return pattern_DownloadUrl;
            }
        }

        /// <summary>
        /// 更新说明,如"更新了小数点精度问题"
        /// </summary>
        protected string Pattern_Readme
        {
            get
            {
                string pattern_Readme =
                    @"<span\s{1,}id=""" +
                    _appUniqueMark +
                    SuffixID_Readme +
                    @"""\s{0,}>\s{0,}\S{1,}\s{0,}</span>";
                return pattern_Readme;
            }
        }

        #endregion

        /// <summary>
        /// 模拟网页请求
        /// </summary>
        private readonly WebClient WwwClient;

        /// <summary>
        /// 更新版本号所在网址
        /// </summary>
        private Uri _updateVerUri;

        /// <summary>
        /// 唯一标识字符
        /// </summary>
        private string _appUniqueMark;

        /// <summary>
        /// 模拟浏览器(用户代码标识)
        /// </summary>
        private const string USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";

        /// <summary>
        /// 构造(调用示例:new UpdateChecker(new Uri(UpdateChecker.UpdateCheckUrl)).CheckAsync();)
        /// </summary>
        /// <param name="updateVerUri">更新信息所在网页</param>
        /// <param name="appUniqueMark">唯一标识符</param>
        public UpdateReminder(Uri updateVerUri, string appUniqueMark)
        {
            _appUniqueMark = appUniqueMark;
            _updateVerUri = updateVerUri;

            WwwClient = new WebClient();
            WwwClient.Headers.Add("user-agent", USER_AGENT);
            WwwClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WwwClient_DownloadStringCompleted);
        }

        #region 访问Web_方法1_异步

        /// <summary>
        /// 检查(异步)
        /// </summary>
        public void CheckAsync()
        {
            if (!WwwClient.IsBusy)
            {
                WwwClient.DownloadStringAsync(_updateVerUri);
            }
        }

        /// <summary>
        /// 检查(异步)完成时
        /// </summary>
        private void WwwClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (!e.Cancelled && e.Error == null)
            {
                string textString = (string) e.Result;
                CheckReminder(textString);
            }
            else
            {
                Exception ex = e.Error;
                if (ex != null)
                {
                    //TODO:处理异常
                    //MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        #endregion

        #region 访问Web_方法2_同步

        /// <summary>
        /// 检查
        /// </summary>
        public void Check()
        {
            if (!WwwClient.IsBusy)
            {
                string textString = WwwClient.DownloadString(_updateVerUri);
                CheckReminder(textString);
            }
        }

        #endregion

        #region 提取网页文本

        /// <summary>
        /// 检查新版本信息
        /// </summary>
        private void CheckReminder(string fullHtml)
        {
            if (string.IsNullOrEmpty(fullHtml))
            {
                return;
            }

            string versionStr = ExtractVersion(fullHtml);
            string downloadUrl = ExtractUrl(fullHtml);
            string readmeStr = ExtractReadme(fullHtml);

            if (string.IsNullOrEmpty(versionStr))
            {
                return;
            }

            //版本号(服务器)
            Version vNew = null;
            try
            {
                vNew = new Version(versionStr);
            }
            catch
            {
                //
            }
            if (vNew == null)
            {
                return;
            }

            //版本号(自己)
            Version vMe = null;
            string vMeStr = "0";
            try
            {
                vMe = new Version(Application.ProductVersion);
                vMeStr = vMe.ToString();
            }
            catch
            {
                //
            }
            if (vMe == null)
            {
                return;
            }

            //对比版本
            if (vMe < vNew)
            {
                StringBuilder sbInfo = new StringBuilder();
                sbInfo.AppendLine(string.Format("此软件有更新版本！"));
                sbInfo.AppendLine("");
                sbInfo.AppendLine("现版本号：" + vMeStr);
                sbInfo.AppendLine("新版本号：" + versionStr);
                sbInfo.AppendLine("");
                sbInfo.AppendLine("更新说明：" + readmeStr);
                sbInfo.AppendLine("下载网址：" + downloadUrl);
                sbInfo.AppendLine("");
                sbInfo.AppendLine("是否打开相关更新网址？");//下载

                DialogResult dlgR = MessageBox.Show(sbInfo.ToString(), "更新", MessageBoxButtons.YesNo,
                                                    MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
                if (dlgR == DialogResult.Yes)
                {
                    //Process.Start(downloadUrl);//下载网址
                    Process.Start(_updateVerUri.ToString());//软件主页
                }
            }
        }

        /// <summary>
        /// 提取Version
        /// </summary>
        private string ExtractVersion(string fullHtml)
        {
            MatchCollection coll = Regex.Matches(fullHtml, Pattern_Version, RegexOptions.IgnoreCase);
            if (coll.Count > 0)
            {
                Group gp = coll[0];

                //
                string s = gp.Value;
                int start = s.IndexOf(">", 0, System.StringComparison.Ordinal);
                int end = s.IndexOf(@"</span>", System.StringComparison.Ordinal);
                //Debug.WriteLine("start = " + start + "end=" + end);
                //Debug.WriteLine(s.Substring(start + 1, end - start - 1));
                return s.Substring(start + 1, end - start - 1);
            }
            return string.Empty;
        }

        /// <summary>
        /// 提取Url
        /// </summary>
        private string ExtractUrl(string fullHtml)
        {
            MatchCollection col2 = Regex.Matches(fullHtml, Pattern_DownloadUrl, RegexOptions.IgnoreCase);
            if (col2.Count > 0)
            {
                Group gp = col2[0];

                //
                string s = gp.Value;
                int start = s.IndexOf(">", 0, System.StringComparison.Ordinal);
                int end = s.IndexOf(@"</span>", System.StringComparison.Ordinal);
                //Debug.WriteLine("start = " + start + "end=" + end);
                //Debug.WriteLine(s.Substring(start + 1, end - start - 1));
                return s.Substring(start + 1, end - start - 1);
            }
            return string.Empty;
        }

        /// <summary>
        /// 提取Readme
        /// </summary>
        private string ExtractReadme(string fullHtml)
        {
            MatchCollection col3 = Regex.Matches(fullHtml, Pattern_Readme, RegexOptions.IgnoreCase);
            if (col3.Count > 0)
            {
                Group gp = col3[0];

                //
                string s = gp.Value;
                int start = s.IndexOf(">", 0, System.StringComparison.Ordinal);
                int end = s.IndexOf(@"</span>", System.StringComparison.Ordinal);
                //Debug.WriteLine("start = " + start + "end=" + end);
                //Debug.WriteLine(s.Substring(start + 1, end - start - 1));
                return s.Substring(start + 1, end - start - 1);
            }
            return string.Empty;
        }

        #endregion

    }
}